package com.hotec.PROJECT_NAME.config.encrypt;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Maps;
import com.hotec.PROJECT_NAME.component.basic.JsonContent;
import com.hotec.PROJECT_NAME.utils.Utils3DES;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;

public class MyHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
    private RequestResponseBodyMethodProcessor target = null;

    public MyHandlerMethodReturnValueHandler(RequestResponseBodyMethodProcessor target) {
        this.target = target;
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        Class<?> controllerClass = returnType.getContainingClass();

        return controllerClass.isAnnotationPresent(RestController.class)
                || controllerClass.isAnnotationPresent(ResponseBody.class)
                || Objects.nonNull(returnType.getMethodAnnotation(ResponseBody.class));
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        HttpServletRequest httpServletRequest = Objects.requireNonNull(webRequest.getNativeRequest(HttpServletRequest.class));

        ApiEncrypt apiEncrypt = returnType.getMethodAnnotation(ApiEncrypt.class);

        boolean ignoreEncrypt = ObjectUtil.isNull(apiEncrypt) || !apiEncrypt.responseEncrypt();

        if(httpServletRequest instanceof MultipartRequest || ignoreEncrypt){
            target.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
        }else{
            Object response = null;

            if(returnValue instanceof JsonContent){
                JsonContent jsonContent = (JsonContent) returnValue;

                String encrypt = Utils3DES.encrypt(JSON.toJSONString(jsonContent.getData(), SerializerFeature.DisableCircularReferenceDetect));

                jsonContent.setData(encrypt);

                response = jsonContent;
            }else if(returnValue instanceof String){
                response = Utils3DES.encrypt((String) returnValue);
            }else if(returnValue instanceof Map){
                Map<String, Object> returnValueMap = Convert.convert(new TypeReference<Map<String, Object>>(){}, returnValue);

                Object data = returnValueMap.getOrDefault("data", Maps.newHashMap());

                returnValueMap.put("data", Utils3DES.encrypt(JSON.toJSONString(data)));

                response = returnValueMap;
            }else{
                response = Utils3DES.encrypt(JSON.toJSONString(returnValue));
            }

            target.handleReturnValue(response, returnType, mavContainer, webRequest);
        }
    }
}
